package com.zxd.interview.util.reflect;

import com.zxd.interview.util.ArrayUtils;
import com.zxd.interview.util.CollectionUtils;
import com.zxd.interview.util.date.DateHelper;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.*;

/**
 * 反射工具类
 *
 * @author zhaoxudong
 * @date 2021/05/18
 */
public abstract class ReflectUtils {
    /**
     * 反射实例化的数组默认长度
     */
    private static final int DEFAULT_ARRAY_LENGTH = 16;

    private ReflectUtils() {
        throw new AssertionError("工具类不允许实例化");
    }

    /**
     * 反射创建无参实例
     */
    public static <T> T create(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException e) {
            throw new AssertionError("不能实例化" + clazz.getName() + ", 请查看该类是否为无法被实例化的类, 如接口, 抽象类, 或者没有无参构造函数.", e);
        } catch (IllegalAccessException e) {
            throw new AssertionError("不能访问" + clazz.getName() + ", 请查看该类的构造函数是否为private", e);
        }
    }

    /**
     * 反射创建一个数组, 默认长度为16
     *
     * @param clazz 类型
     * @return 数组
     */
    public static <T> T[] createArray(Class<T> clazz) {
        return createArray(clazz, DEFAULT_ARRAY_LENGTH);
    }

    /**
     * 反射创建一个数组
     *
     * @param clazz  类型
     * @param length 数组长度
     * @return 数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] createArray(Class<T> clazz, int length) {
        return (T[]) Array.newInstance(clazz, length);
    }

    /**
     * 获取 collection 集合中子元素的泛型类型
     *
     * @param collection 集合
     * @return Class类
     */
    @SuppressWarnings("unchecked")
    public static <T> Class<T> getElementClass(Collection<T> collection) {
        if (CollectionUtils.isEmpty(collection)) {
            return null;
        }
        return (Class<T>) collection.iterator().next().getClass();
    }

    /**
     * 获取数组中子元素的泛型类型
     *
     * @param array 数组
     * @return Class类
     */
    @SuppressWarnings("unchecked")
    public static <T> Class<T> getElementClass(T... array) {
        if (ArrayUtils.isEmpty(array)) {
            return null;
        }
        return (Class<T>) array[0].getClass();
    }

    /**
     * 获取所有的字段信息
     *
     * @param obj 对象
     * @return
     */
    public static List<Field> getAllField(Object obj) {
        if (obj == null) {
            return Collections.emptyList();
        }
        List<Field> fields = new ArrayList<>();
        Class<?> clazz = obj.getClass();
        while (clazz != null) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fields;
    }

    public static Field getField(Object obj, String fieldName) throws NoSuchFieldException {
        if (obj == null || StringUtils.isEmpty(fieldName)) {
            return null;
        }
        Class<?> clazz = obj.getClass();

        Field field = null;
        while (clazz != null && field == null) {
            field = clazz.getDeclaredField(fieldName);
            clazz = clazz.getSuperclass();
        }
        return field;

    }

    public static <T> T getValue(Object obj, String fieldName) throws NoSuchFieldException {
        if (obj == null || StringUtils.isEmpty(fieldName)) {
            return null;
        }
        Class<?> clazz = obj.getClass();
        Field field = getField(obj, fieldName);
        return getValue(obj, field);
    }

    public static <T> T getValue(Object obj, Field field) {
        if (CollectionUtils.isOneEmpty(obj, field)) {
            return null;
        }
        Class<?> clazz = obj.getClass();
        boolean accessible = field.isAccessible();
        field.setAccessible(true);
        try {
            return (T) field.get(obj);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            field.setAccessible(accessible);
        }
    }

    public static boolean setValue(Object obj, String fieldName, Object value) throws NoSuchFieldException {
        return setValue(obj, getField(obj, fieldName), value);
    }

    public static boolean setValue(Object obj, Field field, Object value) {
        if (CollectionUtils.isOneEmpty(obj, field)) {
            return false;
        }
        Class<?> typeClazz = field.getType();
        boolean accessible = field.isAccessible();
        field.setAccessible(true);
        try {

            if (typeClazz.equals(Boolean.TYPE)) {
                // 1. 解析为 Boolean
                field.setBoolean(obj, Boolean.parseBoolean(value.toString()));
            } else if (typeClazz.equals(Boolean.class)) {
                field.set(obj, Boolean.valueOf(value.toString()));
            } else if (typeClazz.equals(Byte.TYPE)) {
                // 2. 解析为 Byte
                field.setByte(obj, Byte.parseByte(value.toString()));
            } else if (typeClazz.equals(Byte.class)) {
                field.set(obj, Byte.valueOf(value.toString()));
            } else if (typeClazz.equals(Character.TYPE)) {
                // 3. 解析为 Char
                String chars = value.toString();
                if (StringUtils.isNotEmpty(chars)) {
                    field.setChar(obj, chars.charAt(0));
                }
            } else if (typeClazz.equals(Character.class)) {
                String chars = value.toString();
                if (StringUtils.isNotEmpty(chars)) {
                    field.set(obj, chars.charAt(0));
                }
            } else if (typeClazz.equals(Short.TYPE)) {
                // 4. 解析为 Short
                field.setShort(obj, Short.parseShort(value.toString()));
            } else if (typeClazz.equals(Short.class)) {
                field.set(obj, Short.valueOf(value.toString()));
            } else if (typeClazz.equals(Integer.TYPE)) {
                // 5. 解析为 Int
                field.setInt(obj, Integer.parseInt(value.toString()));
            } else if (typeClazz.equals(Integer.class)) {
                field.set(obj, Integer.valueOf(value.toString()));
            } else if (typeClazz.equals(Long.TYPE)) {
                // 6. 解析为 Long
                field.setLong(obj, Long.parseLong(value.toString()));
            } else if (typeClazz.equals(Long.class)) {
                field.set(obj, Long.valueOf(value.toString()));
            } else if (typeClazz.equals(Float.TYPE)) {
                // 7. 解析为 Float
                field.setFloat(obj, Float.parseFloat(value.toString()));
            } else if (typeClazz.equals(Float.class)) {
                field.set(obj, Float.valueOf(value.toString()));
            } else if (typeClazz.equals(Double.TYPE)) {
                // 8. 解析为 Double
                field.setDouble(obj, Double.parseDouble(value.toString()));
            } else if (typeClazz.equals(Double.class)) {
                field.set(obj, Double.valueOf(value.toString()));
            } else if (typeClazz.equals(String.class)) {
                // 9. 解析为 String
                field.set(obj, value.toString());
            } else if (typeClazz.equals(Date.class)) {
                // 10. 解析为 Date
                field.set(obj, DateHelper.getDate(value.toString(), "yyyy-MM-dd hh:mm:ss"));
            } else {
                // 解析失败
                return false;
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            field.setAccessible(accessible);
        }
        return true;
    }
}
